# -*- coding: UTF-8 -*-
"""
Ce module contient la classe qui représente la vue de la PlancheDeJeu.
"""
from Tkinter import *
from LignePlancheDeJeu import *
from Joueur import HAUT,BAS,DROITE,GAUCHE
from ConstantesFrogger import *

try:
    from wPIL import Image, ImageTk, ImageOps
except ImportError:
    try:
        from PIL import Image, ImageTk, ImageOps
    except ImportError:
        import sys
        import tkMessageBox
        tkMessageBox.showwarning("Erreur", "S.V.P. Installez PIL pour jouer sur ce système d'exploitation")
        sys.exit()

class VuePlancheDeJeu(Frame):
    """ Classe qui représente la vue d'une PlancheDeJeu. """
    def __init__(self, master, controleur, largeur, hauteur, **params):
        """ Attributs d'une VuePlancheDeJeu:
            - master: L'élément graphique parent de la VuePlancheDeJeu
            - largeur: La largeur du frame
            - largeur: La hauteur du frame
            - listenersDeTouches: Les listeners de touches (HAUT/BAS/DROITE/GAUCHE)
            - imgJoueur: Le sprite de la grenouille
            - largeurUnite: La largeur (px) d'une unité de la planche de jeu
            - hauteurUnite: La hauteur (px) d'une unité de la planche de jeu
        """
        Frame.__init__(self, master, width=largeur, height=hauteur)
        self.master = master
        self.controleur = controleur
        
        self.largeur = largeur
        self.hauteur = hauteur
        
        self.canvas = Canvas(self, width=largeur, height=hauteur)
        
        self.imgRawJoueur = Image.open("../images/frog_"+self.controleur.pdj.getJoueur().couleur + ".png")
        self.imgJoueur = ImageTk.PhotoImage(self.imgRawJoueur)

        self.imgRawMort = Image.open("../images/mort.png")
        self.imgMort = ImageTk.PhotoImage(self.imgRawMort)
        
        self.imgRawElems = {Voiture:"../images/voiture.png", Camion:"../images/camion.png", Pont:"../images/billot.png", Anse:"../images/vide.png", Tortue:"../images/tortue.png"}
        self.imgElems = {}
        for i in self.imgRawElems.items():
            self.imgRawElems[i[0]] = Image.open(i[1])
            self.imgElems[i[0]] = ImageTk.PhotoImage(self.imgRawElems.get(i[0]))

        self.largeurUnite = 0
        self.hauteurUnite = 0
        self.nextUpdate = -1

        self.reverseImgElems = {}
        self.reverseImgElems[Voiture] = ImageTk.PhotoImage(ImageOps.mirror(self.imgRawElems[Voiture]))
        self.reverseImgElems[Camion] = ImageTk.PhotoImage(ImageOps.mirror(self.imgRawElems[Camion]))

        self.ancienNbLignes = 0
        self.setDimensions(controleur.pdj)
        
        self.canvas.pack()
        
    def pause(self):
        self.actif = False
        self.after_cancel(self.nextUpdate)
        try:
            for l in self.listenersDeTouches:
                self.after(50 , lambda  : self.unbind_all(l))
        except:
            pass
        
    
    def unbind_all(self, l):
        try:
            Frame.unbind_all(self, l)
        except:
            pass
    
    def start(self):
        self.actif = True
        self.listenersDeTouches = [
                                self.bind_all("<Up>", lambda x:self.controleur.deplacement(True,HAUT)),
                                self.bind_all("<Down>", lambda x:self.controleur.deplacement(True,BAS)),
                                self.bind_all("<Right>", lambda x:self.controleur.deplacement(True,DROITE)),
                                self.bind_all("<Left>", lambda x:self.controleur.deplacement(True,GAUCHE)),
                                self.bind_all("<KeyRelease-Right>", lambda x:self.controleur.deplacement(False,DROITE)),
                                self.bind_all("<KeyRelease-Left>", lambda x:self.controleur.deplacement(False,GAUCHE))
                            ]
        """[
                                self.bind_all("<Up>", lambda x:self.controleur.deplacement(HAUT)),
                                self.bind_all("<Down>", lambda x:self.controleur.deplacement(BAS)),
                                self.bind_all("<Right>", lambda x:self.controleur.deplacement(DROITE)),
                                self.bind_all("<Left>", lambda x:self.controleur.deplacement(GAUCHE)),
                            ]"""
        self.nextUpdate = self.after(1, lambda  : self.updateMap(self.controleur.pdj, True));
    
    def setDimensions(self, plancheDeJeu):
        """ Méthode qui doit être apellée lorsque la vue doit être redimensionnée 
        ou lorsque l'on rajoute des lignes. Elle calcule les unités de distance et 
        redimensionne les sprites à partir d'une PlancheDeJeu. """
        self.largeurUnite = (self.largeur/plancheDeJeu.getLargeur())
        p = plancheDeJeu.getListeLignes()
        self.hauteurUnite = self.hauteur/len(p)
        self.ancienNbLignes = len(p)
        joueur = plancheDeJeu.getJoueur()
        #self.imgJoueur = self.imgJoueur.zoom((self.largeurUnite/self.imgJoueur.width())*joueur.largeur,(self.hauteurUnite/self.imgJoueur.height())*joueur.hauteur)
        width = self.largeurUnite * plancheDeJeu.getJoueur().largeur
        height = self.hauteurUnite * plancheDeJeu.getJoueur().hauteur
        self.imgRawJoueur = self.imgRawJoueur.resize((width, height), Image.ANTIALIAS)
        self.imgJoueur = ImageTk.PhotoImage(self.imgRawJoueur)
        
        self.imgRawMort = self.imgRawMort.resize((self.largeur/3, self.hauteur/2), Image.ANTIALIAS)
        self.imgRawMort = self.imgRawMort.convert("RGBA")
        self.imgMort = ImageTk.PhotoImage(self.imgRawMort)
        
        for i in self.imgElems.items():
            width = self.largeurUnite * i[0].largeurUnite
            height = self.hauteurUnite -2
            self.imgRawElems[i[0]] = self.imgRawElems[i[0]].resize((width+5,height), Image.ANTIALIAS)
            self.imgElems[i[0]] = ImageTk.PhotoImage(self.imgRawElems.get(i[0]))
            
        for i in self.reverseImgElems.items():
            width = self.largeurUnite * i[0].largeurUnite
            height = self.hauteurUnite -2
            self.imgRawElems[i[0]] = self.imgRawElems[i[0]].resize((width+5,height), Image.ANTIALIAS)
            self.reverseImgElems[i[0]] = ImageTk.PhotoImage(ImageOps.mirror(self.imgRawElems.get(i[0])))

        self.canvas.config(width=self.largeurUnite*plancheDeJeu.getLargeur())
            
    def updateMap(self, plancheDeJeu, repeat =  False):
        """ Cette méthode redessine tout le canvas à partir d'une PlancheDeJeu. """
        if not self.actif:
            return
        largeurUnite = self.largeurUnite
        hauteurUnite = self.hauteurUnite
        lignes = plancheDeJeu.getListeLignes()
        nbLignes = len(lignes)
        if nbLignes != self.ancienNbLignes:
            self.setDimensions(plancheDeJeu)

        try:
            #Tout effacer sur la canvas
            self.canvas.delete(ALL)
    
            #Dessiner les voies
            couleur = {Rue:'black',Riviere:'blue',Trottoir:'gray', Marais:'green'}
            couleursElems = {Voiture:'red',Camion:'gray',Pont:'brown',Anse:'white',Tortue:'green'}
    
            for i in xrange(nbLignes):
                self.canvas.create_rectangle(0, (nbLignes-i-1)*hauteurUnite, self.largeur, (nbLignes-i)*hauteurUnite, fill=couleur[lignes[i].__class__], outline=couleur[lignes[i].__class__])
                    
                #Dessiner les véhicules
                for elem in lignes[i].listeElements:
                    largeur = elem.largeur
                    #self.canvas.create_rectangle(elem.pos.x*largeurUnite, (nbLignes-i-1)*hauteurUnite, (elem.pos.x+largeur)*largeurUnite, ((nbLignes-i)*hauteurUnite), fill=couleursElems[elem.__class__])
                    if(isinstance(elem,Tortue) or isinstance(elem, Pont)):
                        for j in range(elem.largeur):
                            self.canvas.create_image((elem.pos.x+j+0.5)*largeurUnite, (nbLignes-i-1)*hauteurUnite + (hauteurUnite/2.0), image=self.imgElems[elem.__class__])
                    else:
                        if lignes[i].direction >= 0:
                            self.canvas.create_image((elem.pos.x+(elem.largeur/2.0))*largeurUnite, (nbLignes-i-1)*hauteurUnite + (hauteurUnite/2.0),image=self.imgElems[elem.__class__])
                        else:
                            self.canvas.create_image((elem.pos.x+(elem.largeur/2.0))*largeurUnite, (nbLignes-i-1)*hauteurUnite + (hauteurUnite/2.0),image=self.reverseImgElems[elem.__class__])
    
                    if(isinstance(elem, Anse)):
                        if elem.remplie:
                            x = (elem.pos.x + elem.largeur/2.0)*largeurUnite
                            y = ((nbLignes- i - 1) *hauteurUnite + hauteurUnite /2) +3
                            width = (elem.pos.x+largeur)*largeurUnite
                            height = ((nbLignes-i)*hauteurUnite)
                            self.canvas.create_image(x,y,image=self.imgJoueur)
    
            #Dessiner le joueur
            joueur = plancheDeJeu.getJoueur()
            self.canvas.create_image((joueur.pos.x+(joueur.largeur/2.0))*largeurUnite, (nbLignes-joueur.pos.y-joueur.hauteur)*hauteurUnite + (hauteurUnite/2.0),image=self.imgJoueur)
            
            textHeight = hauteurUnite/2
            if plancheDeJeu.getIsFrozen():
                self.canvas.create_text(self.largeur/2, self.hauteur/2, text="Préparez-vous...." , fill="red", font=("Times", str(textHeight*3), "bold"))            
            elif plancheDeJeu.getJoueur().getIsFrozen():
                self.canvas.create_image(self.largeur/2, self.hauteur/2, image=self.imgMort)
                self.canvas.create_text(self.largeur/2, self.hauteur/2+self.imgMort.height()/2+textHeight/2, text="Vous n'êtes pas agile -" + str(ConstantesFrogger.mourrir) + " points" , fill="red", font=("Times", str(textHeight), "bold"))
            
        
        except TclError:
            pass
        finally:
            if self.actif and repeat:
                self.nextUpdate = self.after(50, lambda  : self.updateMap(plancheDeJeu, True))